<template>
  <div class="server-container">
    <el-card>
      <template #header>
        <div class="card-header">
          <span>服务器列表</span>
          <el-button type="primary" @click="handleAdd">新增服务器</el-button>
        </div>
      </template>
      <el-input v-model="serverName" placeholder="请输入菜单名称"
                style="width: 200px; margin-bottom: 10px; margin-right: 10px"/>
      <el-button type="danger" style="margin-bottom: 10px;" @click="search">搜索</el-button>
      <el-button type="info" style="margin-bottom: 10px;" @click="reSet">重置</el-button>
      <el-table :data="serverList" style="width: 100%" border>
        <el-table-column type="index" label="序号" align="center" width="60" fixed/>
        <el-table-column prop="name" label="服务器名称" align="center"/>
        <el-table-column prop="ip" label="IP地址" align="center"/>
        <el-table-column prop="os" label="操作系统" align="center"/>
        <el-table-column prop="port" label="端口号" align="center"/>
        <el-table-column prop="username" label="用户名" align="center"/>
        <el-table-column prop="privateKey" label="私钥" align="center"/>
        <el-table-column prop="status" label="状态" align="center">
          <template #default="{ row }">
            <el-tag :type="row.status === 1 ? 'success' : 'danger'">
              {{ row.status === 1 ? '在线' : '离线' }}
            </el-tag>
          </template>
        </el-table-column>
        <el-table-column prop="createTime" label="创建时间" width="180" align="center">
          <template #default="{ row }">
            {{ row.createTime ? new Date(row.createTime).toLocaleString() : '-' }}
          </template>
        </el-table-column>
        <el-table-column prop="updateTime" label="更新时间" width="180" align="center">
          <template #default="{ row }">
            {{ row.updateTime ? new Date(row.updateTime).toLocaleString() : '-' }}
          </template>
        </el-table-column>
        <el-table-column label="操作" width="250" align="center">
          <template #default="{ row }">
            <el-button type="primary" link @click="handleEdit(row)">编辑</el-button>
            <el-button type="primary" link @click="handleDelete(row)">删除</el-button>
            <el-button
                v-if="hasPermission('server:terminal:connect')"
                type="primary"
                link
                @click="handleMonitor(row)"
            >
              终端
            </el-button>
          </template>
        </el-table-column>
      </el-table>
      <el-pagination
          v-model:current-page="pageNum"
          v-model:page-size="pageSize"
          :page-sizes="[10, 20, 50, 100]"
          :small="false"
          :disabled="false"
          :background="true"
          layout="total, sizes, prev, pager, next, jumper"
          :total="total"
          @size-change="handleSizeChange"
          @current-change="handleCurrentChange"
      />
    </el-card>

    <!-- 新增/编辑服务器弹窗 -->
    <el-dialog
        v-model="dialogVisible"
        :title="isEdit ? '编辑服务器' : '新增服务器'"
        width="600px"
        :close-on-click-modal="false"
        @close="resetForm"
    >
      <el-form
          ref="serverFormRef"
          :model="serverForm"
          :rules="serverRules"
          label-width="100px"
      >
        <el-form-item label="服务器名称" prop="name">
          <el-input v-model="serverForm.name" placeholder="请输入服务器名称"/>
        </el-form-item>
        <el-form-item label="IP地址" prop="ip">
          <el-input v-model="serverForm.ip" placeholder="请输入IP地址"/>
        </el-form-item>
        <el-form-item label="操作系统" prop="os">
          <el-input v-model="serverForm.os" placeholder="请输入操作系统"/>
        </el-form-item>
        <el-form-item label="端口号" prop="port">
          <el-input-number v-model="serverForm.port" :min="1" :max="65535"/>
        </el-form-item>
        <el-form-item label="用户名" prop="username">
          <el-input v-model="serverForm.username" placeholder="请输入登录用户名"/>
        </el-form-item>
        <el-form-item v-if="!isEdit" label="密码" prop="password">
          <el-input v-model="serverForm.password" type="password" show-password placeholder="请输入登录密码"/>
        </el-form-item>
        <el-form-item label="私钥" prop="privateKey">
          <el-input v-model="serverForm.privateKey" type="textarea" :rows="3" placeholder="请输入私钥 (可选)"/>
        </el-form-item>
        <el-form-item label="描述" prop="description">
          <el-input v-model="serverForm.description" type="textarea" :rows="2" placeholder="请输入服务器描述"/>
        </el-form-item>
        <el-form-item label="状态" prop="status">
          <el-radio-group v-model="serverForm.status">
            <el-radio :label="1">启用</el-radio>
            <el-radio :label="0">禁用</el-radio>
          </el-radio-group>
        </el-form-item>
      </el-form>
      <template #footer>
        <span class="dialog-footer">
          <el-button @click="dialogVisible = false">取消</el-button>
          <el-button type="primary" @click="submitForm">确定</el-button>
        </span>
      </template>
    </el-dialog>

    <!-- 终端监控弹窗 -->
    <el-dialog
        v-model="monitorDialogVisible"
        :fullscreen="isMonitorFullscreen"
        height="80vh"
        :close-on-click-modal="false"
        destroy-on-close
        @opened="handleMonitorDialogOpened"
        custom-class="terminal-dialog"
        draggable
        resizable
    >
      <template #header>
        <div class="dialog-header-custom">
          <span>服务器监控 ({{ currentServer.name }})</span>
          <div class="header-actions">
            <el-button-group>
              <el-button
                  :type="activeTab === 'terminal' ? 'primary' : 'default'"
                  @click="activeTab = 'terminal'"
              >
                终端
              </el-button>
            </el-button-group>
            <el-button
                :icon="isMonitorFullscreen ? Aim : FullScreen"
                link
                @click="toggleMonitorFullscreen"
                class="fullscreen-btn"
            />
          </div>
        </div>
      </template>

      <div class="monitor-content">
        <!-- 终端面板 -->
        <div v-show="activeTab === 'terminal'" class="terminal-panel">
          <Terminal
              v-if="monitorDialogVisible && currentServer.id"
              ref="terminalComponentRef"
              :server-id="currentServer.id"
              :server-ip="currentServer.ip"
              :server-port="currentServer.port"
              :username="currentServer.username"
              :password="currentServer.password"
          />
        </div>
      </div>
    </el-dialog>
  </div>
</template>

<script setup lang="ts">
import {ref, reactive, onMounted, nextTick, onUnmounted} from 'vue'
import {ElMessage, ElMessageBox, type FormInstance, type FormRules} from 'element-plus'
import {getServerPage, addServer, updateServer, deleteServer} from '@/api/server'
import Terminal from '@/components/Terminal.vue'
import {FullScreen, Aim} from '@element-plus/icons-vue'
import {usePermission} from '@/hooks/usePermission'

interface SysServer {
  id?: number;
  name: string;
  ip: string;
  ipAddress: string;
  os: string;
  port: number;
  username: string;
  password?: string;
  privateKey?: string;
  description?: string;
  status: number;
  createTime?: string;
  updateTime?: string;
}

const serverList = ref<SysServer[]>([])
const total = ref(0)
const pageNum = ref(1)
const pageSize = ref(10)

const dialogVisible = ref(false)
const isEdit = ref(false)
const serverFormRef = ref<FormInstance>()
const serverForm = reactive<SysServer>({
  name: '',
  ip: '',
  os: '',
  port: 22,
  username: '',
  password: '',
  privateKey: '',
  description: '',
  status: 1,
  ipAddress: '',
})

const monitorDialogVisible = ref(false)
const isMonitorFullscreen = ref(false)
const currentServer = ref<SysServer>({} as SysServer)
const terminalComponentRef = ref<InstanceType<typeof Terminal> | null>(null);

const {hasPermission} = usePermission()

const serverRules = reactive<FormRules>({
  name: [{required: true, message: '请输入服务器名称', trigger: 'blur'}],
  ip: [
    {required: true, message: '请输入IP地址', trigger: 'blur'},
    {
      pattern: /^((25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(25[0-5]|2[0-4]\d|[01]?\d\d?)$/,
      message: '请输入正确的IP地址', trigger: 'blur'
    }
  ],
  os: [{required: true, message: '请输入操作系统', trigger: 'blur'}],
  port: [{required: true, message: '请输入端口号', trigger: 'blur'}],
  username: [{required: true, message: '请输入用户名', trigger: 'blur'}],
  password: [{required: true, message: '请输入密码', trigger: 'blur'}],
  status: [{required: true, message: '请选择状态', trigger: 'change'}],
})
const serverName = ref<string>('')
const search = async () => {
  await fetchServerList()
}
const reSet = async () => {
  serverName.value = ''
  await fetchServerList()
}
const fetchServerList = async () => {
  const res = await getServerPage({pageNum: pageNum.value, pageSize: pageSize.value, serverName: serverName.value})
  if (res.code === 200) {
    serverList.value = res.data.records
    total.value = res.data.total
  }
}

const handleSizeChange = (val: number) => {
  pageSize.value = val
  fetchServerList()
}

const handleCurrentChange = (val: number) => {
  pageNum.value = val
  fetchServerList()
}

const handleAdd = () => {
  isEdit.value = false
  resetForm()
  dialogVisible.value = true
}

const handleEdit = (row: SysServer) => {
  isEdit.value = true
  Object.assign(serverForm, row)
  dialogVisible.value = true
}

const handleDelete = (row: SysServer) => {
  ElMessageBox.confirm(
      `确定要删除服务器 "${row.name}" 吗？`,
      '提示',
      {
        confirmButtonText: '确定',
        cancelButtonText: '取消',
        type: 'warning',
      }
  ).then(async () => {
    const res = await deleteServer(row.id!)
    if (res.code === 200) {
      ElMessage.success('删除成功')
      fetchServerList()
    } else {
      ElMessage.error(res.msg || '删除失败')
    }
  }).catch(() => {
    ElMessage.info('已取消删除')
  })
}

const submitForm = async () => {
  if (!serverFormRef.value) return
  await serverFormRef.value.validate(async (valid) => {
    if (valid) {
      let res
      const dataToSend = {...serverForm};
      dataToSend.ipAddress = dataToSend.ip;
      if (isEdit.value && !dataToSend.password) {
        delete dataToSend.password;
      }
      if (isEdit.value) {
        res = await updateServer(dataToSend)
      } else {
        res = await addServer(dataToSend)
      }
      if (res.code === 200) {
        ElMessage.success(isEdit.value ? '更新成功' : '新增成功')
        dialogVisible.value = false
        fetchServerList()
      } else {
        ElMessage.error(res.msg || (isEdit.value ? '更新失败' : '新增失败'))
      }
    }
  })
}

const resetForm = () => {
  if (serverFormRef.value) {
    serverFormRef.value.resetFields()
  }
  Object.assign(serverForm, {
    name: '',
    ip: '',
    os: '',
    port: 22,
    username: '',
    password: '',
    privateKey: '',
    description: '',
    status: 1,
    ipAddress: '',
  })
}

onMounted(async () => {
  await fetchServerList()
})

const activeTab = ref('terminal')

const handleMonitor = (row: SysServer) => {
  if (!hasPermission('server:terminal:connect')) {
    ElMessage.error('您没有终端连接权限')
    return
  }
  currentServer.value = {...row}
  monitorDialogVisible.value = true
  isMonitorFullscreen.value = false
  activeTab.value = 'terminal'

  nextTick(() => {
    if (terminalComponentRef.value) {
      terminalComponentRef.value.fitTerminal()
    }
  })
}

const handleMonitorDialogOpened = () => {
  nextTick(() => {
    if (terminalComponentRef.value) {
      terminalComponentRef.value.fitTerminal()
    }
  })
}

const toggleMonitorFullscreen = () => {
  isMonitorFullscreen.value = !isMonitorFullscreen.value;
  nextTick(() => {
    if (terminalComponentRef.value && typeof terminalComponentRef.value.fitTerminal === 'function') {
      terminalComponentRef.value.fitTerminal();
    }
  });
};

onUnmounted(() => {
})

window.addEventListener('resize', () => {
})
</script>

<style scoped>
.server-container {
  padding: 20px;
}

.card-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 20px;
}

.el-pagination {
  margin-top: 20px;
  justify-content: flex-end;
}

/* Ensure el-overlay-dialog (the direct parent of el-dialog) behaves correctly in fullscreen */
/* This is a global class, so it needs :deep() if scoped, or be in a global stylesheet */
/* Element Plus automatically adds a class to the body when a dialog is open, so we can use that */
body.el-popup-parent--hidden {
  overflow: hidden !important; /* Hide scrollbar on body when dialog is open */
}

/* Custom styles for the terminal dialog */
.terminal-dialog {
  /* For non-fullscreen, give the dialog a fixed height and hide overflow */

  &:not(.is-fullscreen) {
    height: 70vh; /* Adjust as needed for initial height */
    max-height: 90vh; /* Ensure it doesn't exceed screen height */
    width: 80%; /* Ensure a fixed width */
    position: fixed; /* Position relative to the viewport */
    top: 50%; /* Center vertically */
    left: 50%; /* Center horizontally */
    transform: translate(-50%, -50%); /* Adjust for dialog's own size */
    overflow: hidden; /* Hide scrollbars on the dialog itself */
    display: flex; /* Make the dialog a flex container */
    flex-direction: column; /* Stack children vertically */
  }

  /* Target the internal content wrapper to be a flex container and take full height */
  /* :deep() is needed for scoped styles to target internal Element Plus components */

  :deep(.el-dialog__content) {
    display: flex;
    flex-direction: column;
    flex-grow: 1; /* Allow content to grow and take available space */
    overflow: hidden; /* Important for scrollbars on the dialog content itself */
    min-height: 0; /* Prevent content from pushing out parent */
  }

  /* Ensure the body takes up remaining vertical space and handles overflow */

  :deep(.el-dialog__body) {
    flex-grow: 1; /* Allow body to grow and take available space */
    overflow: hidden; /* Crucial for xterm.js to handle its own scrollbars */
    padding: 0 !important; /* Remove internal padding for xterm.js */
    display: flex; /* Make body a flex container too for its content (Terminal.vue) */
    flex-direction: column;
    min-height: 0; /* Prevent body from pushing out parent */
  }

  /* Adjust header/footer to prevent shrinking */

  :deep(.el-dialog__header),
  :deep(.el-dialog__footer) {
    flex-shrink: 0;
  }

  /* Restore default header padding and border */

  :deep(.el-dialog__header) {
    padding: 15px 20px;
    border-bottom: 1px solid #ebeef5;
    display: flex;
    justify-content: space-between;
    align-items: center;
  }
}

.dialog-header-custom {
  display: flex;
  justify-content: space-between;
  align-items: center;
  width: 100%;
}

.fullscreen-btn {
  font-size: 20px;
  color: #909399;
}

.fullscreen-btn:hover {
  color: #409eff;
}

.monitor-content {
  height: 100%;
  overflow: hidden;
}

.terminal-panel {
  height: 100%;
  overflow: auto;
}

.header-actions {
  display: flex;
  align-items: center;
  gap: 10px;
}

/* 确保弹窗内容区域可以滚动 */
:deep(.el-dialog__body) {
  height: calc(100% - 120px);
  overflow: auto;
  padding: 20px;
}
</style>
